
open Operator_ast

module StrSet = Set.Make(String)
module StrMap = Map.Make(String)

type fullfill = {
	idents : StrSet.t;	(* liste des variables déclarées *)
	operators : StrSet.t;
}

let fullfill_list func (data :fullfill) lst = 
	List.fold_left (fun data e -> func data e) data lst

let rec fullfill_sourceElement data = function
	| AStatement(s) -> fullfill_statement data s
	(*| AFunctionDeclaration(funcDecl) -> fullfill_functionDeclaration data funcDecl *) (* Modif #1 *)
	
and fullfill_statement data = function
	| ABlock(block) -> fullfill_block data block
	| AClassStatement cs -> fullfill_classStatement data cs
	| AOperatorAssignment op -> fullfill_operatorAssignment data op
	| AOperatorUnassignment un -> fullfill_operatorUnassignment data un
	| AVariableStatement(varStmt) -> fullfill_variableStatement data varStmt
	| AConstStatement(varStmt) -> fullfill_variableStatement data varStmt		(* Modif #2 *)
	| AFuncDeclaration(funcDecl) -> fullfill_functionDeclaration data funcDecl	(* Modif #1 *)
	| AIfStatement(ifStatement) -> fullfill_ifStatement data ifStatement
	| AIterationStatement(iterationStatement) -> fullfill_iterationStatement data iterationStatement
	| AWithStatement(withStatement) -> fullfill_withStatement data withStatement
	| ALabelledStatement(labelledStatement) -> fullfill_labelledStatement data labelledStatement
	| ASwitchStatement(switchStatement) -> fullfill_switchStatement data switchStatement
	| ATryStatement(tryStatement) -> fullfill_tryStatement data tryStatement
	| AEmptyStatement -> data
	| AExpressionStatement _ -> data
	| AContinueStatement _ -> data
	| ABreakStatement _ -> data
	| AReturnStatement _ -> data
	| AThrowStatement _ -> data
	| ADebuggerStatement -> data

and fullfill_operatorAssignment data (op, _) =
	{
		idents = data.idents;
		operators = StrSet.add op data.operators
	}
	
and fullfill_operatorUnassignment data op =
	{
		idents = data.idents;
		operators = StrSet.add op data.operators
	}

and fullfill_classStatement data (_,_,ident,_,classElements) =
	let data = {
		idents = StrSet.add ident data.idents;
		operators = data.operators
	} in
	fullfill_list fullfill_classElement data classElements

and fullfill_classElement data = function
	| ACVariableStatement vs -> fullfill_variableStatement data vs
	| ACConstStatement cs -> fullfill_variableStatement data cs
	| ACFuncDeclaration funcDecl -> fullfill_functionDeclaration data funcDecl

and fullfill_block data block =
	fullfill_list fullfill_statement data block

and fullfill_variableStatement data (_, _,stmt) =
	fullfill_variableDeclarationList data stmt
	
and fullfill_variableDeclarationList data decls =
	fullfill_list fullfill_variableDeclaration data decls

and fullfill_variableDeclaration data (ident,init) = 
	{
		idents = (StrSet.add ident data.idents);
		operators = data.operators
	}

and fullfill_functionDeclaration data (is_local, _, _, ident, params, body) =
	{
		idents = (StrSet.add ident data.idents);
		operators = data.operators
	}
	
and fullfill_ifStatement data = function
	| AIfElse(expr, stmt1, stmt2) ->
		let data = fullfill_statement data stmt1 in
		fullfill_statement data stmt2
	| AIf(expr, stmt) ->
		fullfill_statement data stmt

and fullfill_iterationStatement data = function
	| ADoWhile(stmt, expr) ->
		fullfill_statement data stmt
	| AWhile(expr, stmt) ->
		fullfill_statement data stmt
	| AFor(expr1, expr2, expr3, stmt) ->
		fullfill_statement data stmt
	| AForIn(lhs, expr, stmt) ->
		fullfill_statement data stmt
	| AForVar(_, varDecls, expr1, expr2, stmt) ->
		let data = fullfill_variableDeclarationList data varDecls in
		fullfill_statement data stmt
	| AForVarIn(_, varDecl, expr, stmt) ->
		let data = fullfill_variableDeclaration data varDecl in
		fullfill_statement data stmt
		
and fullfill_withStatement data (_, stmt) = 
	fullfill_statement data stmt

and fullfill_labelledStatement data (_, stmt) =
	fullfill_statement data stmt
	
and fullfill_switchStatement data (_, caseBlock) = 
	fullfill_caseBlock data caseBlock

and fullfill_caseBlock data = function
	| ACasesNoDefault(caseClauses) -> 
		fullfill_caseClauses data caseClauses
	| ACasesDefault(caseClauses1, defaultClause, caseClauses2) ->
		let data = fullfill_caseClauses data caseClauses1 in
		let data = fullfill_defaultClause data defaultClause in
		fullfill_caseClauses data caseClauses2

and fullfill_defaultClause data stmts =
	fullfill_list fullfill_statement data stmts

and fullfill_caseClauses data clauses = 
	fullfill_list fullfill_caseClause data clauses;
	
and fullfill_caseClause data (expr,stmts) =
	fullfill_list fullfill_statement data stmts

and fullfill_tryStatement data = function
	| ATryCatch(block, catch) ->
		let data = fullfill_block data block in
		fullfill_catch data catch
	| ATryFinally(block, finally) ->
		let data = fullfill_block data block in
		fullfill_finally data finally
	| ATryCatchFinally(block, catch, finally) ->
		let data = fullfill_block data block in
		let data = fullfill_catch data catch in
		fullfill_finally data finally

and fullfill_catch data (ident,block) =
	let data = {
		idents = StrSet.add ident data.idents;
		operators = data.operators
	} in
	fullfill_block data block

and fullfill_finally data block =
	fullfill_block data block

and fullfill_functionContent params body =
	fullfill_list fullfill_sourceElement {
		idents = fullfill_params StrSet.empty params;
		operators = StrSet.empty
	} body

and fullfill_params set params = 
	List.fold_left (fun set ident -> StrSet.add ident set) set params
	
